﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
using T.FAS.Runtime.Action.SPI;
using T.FAS.Runtime.Metadata.Entity;

namespace T.FAS.Runtime.Action.Service
{
    class ActionRTPLocalCache
    {
        private Dictionary<string, DateTime> metadataCache;

        private Dictionary<string, ActionInfoWithSchema> schemaCache;

        private ConcurrentDictionary<string, DateTime> cdoCache;
        private ConcurrentDictionary<string, List<ActionMetaDataView>> actionViewCache;

        private static ActionRTPRedisCache redisCache = null;

        private static readonly object syncobj = new object();

        private static ActionRTPLocalCache instance;

        private ActionRTPLocalCache()
        {
            metadataCache = new Dictionary<string, DateTime>();
            schemaCache = new Dictionary<string, ActionInfoWithSchema>();
            cdoCache = new ConcurrentDictionary<string, DateTime>();
            actionViewCache = new ConcurrentDictionary<string, List<ActionMetaDataView>>();
        }

        public static ActionRTPLocalCache GetInstance()
        {
            if (instance == null)
            {
                lock (syncobj)
                {
                    if (instance == null)
                    {
                        instance = new ActionRTPLocalCache();
                        redisCache = new ActionRTPRedisCache();
                    }
                }
            }

            return instance;
        }

        public ActionInfoWithSchema GetSchema(IMetaDataContent metaData)
        {
            if (schemaCache.ContainsKey(metaData.MetaDataID) == false)
            {
                return GetSchemaFromRedis(metaData);
            }

            if (metadataCache.ContainsKey(metaData.MetaDataID) == false)
            {
                return GetSchemaFromRedis(metaData);
            }

            var cachedMetaDataLastModifyTime = metadataCache[metaData.MetaDataID];
            if (metaData.LastModifyTime != cachedMetaDataLastModifyTime)
            {
                if (schemaCache.ContainsKey(metaData.MetaDataID))
                    schemaCache.Remove(metaData.MetaDataID);

                if (metadataCache.ContainsKey(metaData.MetaDataID))
                    metadataCache.Remove(metaData.MetaDataID);

                redisCache.Remove(metaData.MetaDataID);

                return null;
            }

            var schema = schemaCache[metaData.MetaDataID];
            return schema;
        }
        public ActionInfoWithSchema GetSchemaFromRedis(IMetaDataContent metaData)
        {
            try
            {
                var cacheTimeStamp = redisCache.GetTimeStamp(metaData.MetaDataID);
                var curTimeStamp = ActionRTPUtil.GetTimeStamp(metaData.LastModifyTime);
                if (cacheTimeStamp == curTimeStamp)
                {
                    return redisCache.Get(metaData.MetaDataID);
                }
                else
                    return null;
            }
            catch
            {
                return null;
            }
        }

        public void AddCache(IMetaDataContent metaData, ActionInfoWithSchema schema)
        {
            schemaCache[metaData.MetaDataID]= schema;
            metadataCache[metaData.MetaDataID] = metaData.LastModifyTime;
            redisCache.Add(schema);
        }
        public void AddActionViewCache(IMetaDataContent metaData,List<ActionMetaDataView> actions)
        {
            cdoCache[metaData.MetaDataID] = metaData.LastModifyTime;
            actionViewCache[metaData.MetaDataID] = actions;
        }
        public List<ActionMetaDataView> GetCDOActionMetadataViews(IMetaDataContent cdoMetadata)
        {
            if (cdoCache.ContainsKey(cdoMetadata.MetaDataID) == false)
            {
                return null;
            }
            if (actionViewCache.ContainsKey(cdoMetadata.MetaDataID) == false)
            {
                return null;
            }
            var cachedMetaDataLastModifyTime = cdoCache[cdoMetadata.MetaDataID];
            if (cdoMetadata.LastModifyTime != cachedMetaDataLastModifyTime)
            {
                if (actionViewCache.ContainsKey(cdoMetadata.MetaDataID))
                    actionViewCache.TryRemove(cdoMetadata.MetaDataID, out List<ActionMetaDataView> actViews);

                if (cdoCache.ContainsKey(cdoMetadata.MetaDataID))
                    cdoCache.TryRemove(cdoMetadata.MetaDataID, out DateTime dt);
                return null;
            }

            return actionViewCache[cdoMetadata.MetaDataID];
        }
    }
}
